package com.jaiky.imagespickers.camera;
/*

 * Copyright (C) 2021 Huawei Device Co., Ltd.

 * Licensed under the Apache License, Version 2.0 (the "License");

 * you may not use this file except in compliance with the License.

 * You may obtain a copy of the License at

 *

 *     http://www.apache.org/licenses/LICENSE-2.0

 *

 * Unless required by applicable law or agreed to in writing, software

 * distributed under the License is distributed on an "AS IS" BASIS,

 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

 * See the License for the specific language governing permissions and

 * limitations under the License.

 */


import ohos.agp.graphics.Surface;
import ohos.agp.graphics.SurfaceOps;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.media.camera.CameraKit;
import ohos.media.camera.device.*;
import ohos.media.camera.params.Metadata;
import ohos.media.common.VideoProperty;
import ohos.media.image.ImageReceiver;
import ohos.media.image.common.ImageFormat;
import ohos.media.image.common.Size;

import java.util.ArrayList;
import java.util.List;

/**
 * description : CameraManager
 *
 * @since 2021-04-15
 */
public class CameraManager implements SurfaceOps.Callback {
    private Context mContext;
    private CameraView mCameraView;
    private boolean isRecording = false;
    private Surface previewSurface;
    private Camera cameraDevice;
    private CameraConfig.Builder cameraConfigBuilder;
    private ImageReceiver imageReceiver;
    private int flashMode = Metadata.FlashMode.FLASH_CLOSE;
    private ImageReceiver.IImageArrivalListener imageArrivalListener;
    private VideoProperty.Builder videoPropertyBuilder;
    private CameraAbility commCamera;
    private EventHandler eventHandler;
    private boolean isFrontCamera;

    /**
     * 初始化 CameraManager
     *
     * @param context    context
     * @param cameraView cameraView
     */
    public CameraManager(Context context, CameraView cameraView) {
        mContext = context;
        mCameraView = cameraView;
        isFrontCamera = mCameraView.isFrontCamera();
        initVariable();
    }

    @Override
    public void surfaceCreated(SurfaceOps surfaceOps) {
        surfaceOps.setFixedSize(mCameraView.getHeight(), mCameraView.getWidth());
        previewSurface = surfaceOps.getSurface();
        mContext.getUITaskDispatcher().asyncDispatch(() -> {
            if (!cameraInit()) {
                mContext.terminateAbility();
            }
            takePhotoInit();
        });
    }

    @Override
    public void surfaceChanged(SurfaceOps surfaceOps, int i1, int i2, int i3) {
    }

    @Override
    public void surfaceDestroyed(SurfaceOps surfaceOps) {
        // 释放相机设备
        if (cameraDevice != null) {
            // 关闭相机和释放资源
            cameraDevice.release();
        }
    }

    private boolean cameraInit() {
        isFrontCamera = mCameraView.isFrontCamera();
        CameraKit camerakit = CameraKit.getInstance(mContext.getApplicationContext());
        if (camerakit == null || camerakit.getCameraIds().length <= 0) {
            return false;
        }
        String cameraId = camerakit.getCameraIds()[0];
        if (camerakit.getCameraIds().length > 1) {
            cameraId = isFrontCamera ? camerakit.getCameraIds()[1] : camerakit.getCameraIds()[0];
        }
        commCamera = camerakit.getCameraAbility(cameraId);
        if (commCamera == null) {
            return false;
        }
        CameraStateCallback cameraStateCallback = new MyCameraStatusCallback();
        camerakit.createCamera(cameraId, cameraStateCallback, eventHandler);
        return true;
    }

    private void initVariable() {
        eventHandler = new EventHandler(EventRunner.current());
    }

    private void takePhotoInit() {
        // 获取拍照支持分辨率列表
        List<Size> pictureSizes = getSupportedSizes();
        if (pictureSizes != null && pictureSizes.size() > 0) {
            // 根据拍照要求选择合适的分辨率
            setPhotoSize(pictureSizes.get(0));
        }
    }

    /**
     * 开始拍照
     */
    public void capture() {
        // 获取拍照配置模板
        if (cameraDevice != null){
            FrameConfig.Builder pictureFrameConfigBuilder =
                    cameraDevice.getFrameConfigBuilder(Camera.FrameConfigType.FRAME_CONFIG_PICTURE);
            // 配置拍照surface
            pictureFrameConfigBuilder.addSurface(imageReceiver.getRecevingSurface());
            pictureFrameConfigBuilder.setFlashMode(flashMode);
            pictureFrameConfigBuilder.setImageRotation(90);
            // 启动拍照
            cameraDevice.triggerSingleCapture(pictureFrameConfigBuilder.build());
        }
    }


    /**
     * 设置拍照监听
     *
     * @param imageArrivalListener 拍照监听
     */
    public void setImageArrivalListener(ImageReceiver.IImageArrivalListener imageArrivalListener) {
        this.imageArrivalListener = imageArrivalListener;
    }

    private void setPhotoSize(Size size) {
        // 创建ImageReceiver对象，注意creat函数中宽度要大于高度；5为最大支持的图像数，请根据实际设置
        imageReceiver =
                ImageReceiver.create(
                        Math.max(size.width, size.height), Math.min(size.width, size.height), ImageFormat.JPEG, 1);
        if (imageArrivalListener != null) {
            imageReceiver.setImageArrivalListener(imageArrivalListener);
        }
    }

    private List<Size> getSupportedSizes() {
        if (commCamera != null) {
            return commCamera.getSupportedSizes(SurfaceOps.class);
        } else {
            return new ArrayList<>();
        }
    }

    /**
     * 设置录像大小
     *
     * @param size 录像大小
     */
    public void setRecordrSize(Size size) {
        videoPropertyBuilder.setRecorderHeight(Math.min(size.height, size.width));
        videoPropertyBuilder.setRecorderWidth(Math.max(size.height, size.width));
    }

    /**
     * set CameraFlashMode
     *
     * @param flashMode CameraFlashMode
     */
    public void setCameraFlashMode(int flashMode) {
        this.flashMode = flashMode;
    }

    /**
     * 切换前/后置摄像头
     */
    public void switchCamera() {
        switchCamera(!isFrontCamera);
    }

    /**
     * 切换前/后置摄像头
     *
     * @param isFrontCamera 是否切换至前置摄像头；true：前置； false：后置
     */
    public void switchCamera(boolean isFrontCamera) {
        this.isFrontCamera = isFrontCamera;
        cameraInit();
    }

    /**
     * 是否正在录像
     *
     * @return true：正在录像； false：不在录像
     */
    public boolean isRecording() {
        return isRecording;
    }

    private class MyCameraStatusCallback extends CameraStateCallback {
        @Override
        public void onCreated(Camera camera) {
            super.onCreated(camera);
            cameraDevice = camera;
            cameraConfigBuilder = camera.getCameraConfigBuilder();
            if (cameraConfigBuilder == null) {
                return;
            }
            CameraConfig cameraConfig =
                    cameraConfigBuilder
                            // 配置预览的Surface
                            .addSurface(previewSurface)
                            // 配置拍照的Surface
                            .addSurface(imageReceiver.getRecevingSurface())
                            .build();
            camera.configure(cameraConfig);
        }

        @Override
        public void onCreateFailed(String cameraId, int errorCode) {
            super.onCreateFailed(cameraId, errorCode);
        }

        @Override
        public void onConfigured(Camera camera) {
            // 获取预览配置模板
            FrameConfig.Builder frameConfigBuilder =
                    camera.getFrameConfigBuilder(Camera.FrameConfigType.FRAME_CONFIG_PREVIEW);
            frameConfigBuilder.addSurface(previewSurface);
            frameConfigBuilder.setFlashMode(flashMode);
            // 通过 triggerLoopingCapture(FrameConfig)方法实现循环帧捕获(如预览/录像)。
            camera.triggerLoopingCapture(frameConfigBuilder.build());
        }

        @Override
        public void onConfigureFailed(Camera camera, int errorCode) {
        }

        @Override
        public void onReleased(Camera camera) {
            videoPropertyBuilder = null;
        }

        @Override
        public void onFatalError(Camera camera, int errorCode) {
            super.onFatalError(camera, errorCode);
        }
    }
}
